package anc.tankshooter.network.ui;


import java.util.ArrayList;
import java.util.Random;

import org.andengine.engine.camera.hud.controls.BaseOnScreenControl;
import org.andengine.engine.camera.hud.controls.BaseOnScreenControl.IOnScreenControlListener;
import org.andengine.engine.camera.hud.controls.DigitalOnScreenControl;
import org.andengine.entity.sprite.AnimatedSprite;
import org.andengine.entity.sprite.Sprite;
import org.andengine.input.touch.TouchEvent;

import anc.server.tankshooter.models.Account;
import anc.server.tankshooter.models.Match;
import anc.tankshooter.GameActivity;
import anc.tankshooter.GameSetting;
import anc.tankshooter.controls.FlyText;
import anc.tankshooter.controls.MatchInfoBoard;
import anc.tankshooter.models.Bullet;
import anc.tankshooter.models.Bullet.BulletType;
import anc.tankshooter.models.Explode;
import anc.tankshooter.models.IDymanicObject.MovingDirection;
import anc.tankshooter.models.ITank;
import anc.tankshooter.models.Tank;
import anc.tankshooter.network.CommandList;
import anc.tankshooter.network.GamePlayingListener;
import anc.tankshooter.network.MovePacket;
import anc.tankshooter.network.Packet;
import anc.tankshooter.ui.ConfirmScreen;
import anc.tankshooter.ui.ConfirmScreen.ButtonDialogWatcher;
import anc.tankshooter.ui.IScreen;
import anc.tankshooter.ui.ResourcesManager;
import anc.tankshooter.ui.ResourcesManager.typeMusic;
import anc.tankshooter.ui.ResourcesManager.typeSound;
import anc.tankshooter.ui.SceneManager;
import anc.tankshooter.ui.SceneManager.SceneType;
import anc.tankshooter.ui.SettingScreen;

public class NetworkGameScreen extends IScreen implements Runnable,IOnScreenControlListener {

	private static Random mRadom=new Random();
	/**
	 * Điều khiển xe tăng di chuyển
	 */
	private boolean mIsSendingMove;
	private DigitalOnScreenControl mController;
	private Sprite mShootController;
	
	private AnimatedSprite mPauseButton;
	private AnimatedSprite mSettingButton;

	private Account mMyAccount,mCompetitorAccount;
	private Tank mMyTank,mCompetitorTank;
	private ArrayList<ITank> mItanks;
	private ArrayList<Bullet> mBullets;
	private ArrayList<Explode> mExplodes;
	private ArrayList<FlyText> mFlyTexts;

	private int mPausedPlayer;
	private boolean mIsSetting;
	private MatchInfoBoard mInfoBoard;
	private MatchResultScreen mResultDialogScreen;
	
	private boolean mIsPlaying;
	private Match mMatch;
	private ArrayList<Packet> mPendingPackets;
	private ArrayList<MovePacket> mMovingAction;
	public NetworkGameScreen(Match m ){
		mMatch = m;
		mPendingPackets = new ArrayList<Packet>();
		mMovingAction = new ArrayList<MovePacket>();
		mMyAccount = GameActivity.mClient.getAccount();
		mCompetitorAccount = new Account();
		mCompetitorAccount.setAccountId(mMyAccount.getAccountId()==mMatch.getOwnerId()?mMatch.getCompetitorId():mMatch.getOwnerId());
		mCompetitorAccount.setUsername(mMyAccount.getAccountId()==mMatch.getOwnerId()?mMatch.getCompetitor():mMatch.getOwner());
		
		mMyAccount.setRoomOwner(mMyAccount.getAccountId()==mMatch.getOwnerId());
		mCompetitorAccount.setRoomOwner(mCompetitorAccount.getAccountId()==mMatch.getOwnerId());
		
		mMyTank=new Tank(mMatch.getOwnerId()==mMyAccount.getAccountId()?0:1,0, 0);
		mCompetitorTank=new Tank(mMatch.getOwnerId()==mMyAccount.getAccountId()?1:0,0, 0);
		
		mInfoBoard=new MatchInfoBoard(mMyAccount,mCompetitorAccount,0,0); 
		mInfoBoard.setZIndex(3);
		resetAllInfomation();
		registerPacketListener();
		new Thread(this).start();
	}

	@Override
	public void createScene() 
	{
		mItanks = new ArrayList<ITank>();
		mExplodes = new ArrayList<Explode>();
		mBullets = new ArrayList<Bullet>();
		mFlyTexts = new ArrayList<FlyText>();
		
		
		mController= new DigitalOnScreenControl(32, GameActivity.CAMERA_HEIGHT - 128 - 32, 
				mEngine.getCamera(),
				mResourcesManager.mControllerTexture,
				mResourcesManager.mKnobTexture, 
				0.08f,
				mVertextManager, this);
		
		mController.getControlBase().setAlpha(0.1f);
		mController.getControlBase().setScale(1.5f);
		mController.getControlKnob().setScale(1.5f);
		mController.refreshControlKnobPosition();

		int shootControllerX = GameActivity.CAMERA_WITDH - 96;
		int shootControllerY = GameActivity.CAMERA_HEIGHT - 96 ;
		mShootController = new Sprite(shootControllerX, shootControllerY, mResourcesManager.mShootTexture, mVertextManager) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {
					if(!mIsPause && !mMyTank.isDead()) {
						float location[] = mMyTank.shootAt();
						Packet pk = new Packet(CommandList.CLIENT_FIRE,location[0]+":"+location[1]);
						addPendingPacket(pk);
						mShootController.setAlpha(0.5f);
					}
					return true;
				}else if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP||
						pSceneTouchEvent.getAction() == TouchEvent.ACTION_OUTSIDE)
					mShootController.setAlpha(0.1f);
				return false;
			}
		};
		mShootController.setScale(2f);
		mShootController.setAlpha(0.1f);
		mShootController.setZIndex(3);
		
		
		
		mSettingButton = new AnimatedSprite(740, 5, ResourcesManager.getInstance().mSettingButtonTexture, mVertextManager)
		{
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN)
				{
					this.setCurrentTileIndex(1);
				}
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP)
				{
					if(!mIsSetting)
					{
						this.setCurrentTileIndex(0);
						SettingScreen settingScene = new SettingScreen(new SettingScreen.SettingButtonListener() {
							
							@Override
							public void onOkClicked() {
								clearChildScene();
								mIsSetting = false;
								NetworkGameScreen.this.setChildScene(mController);
							}
							
							@Override
							public void onCancleClicked() {
								NetworkGameScreen.this.clearChildScene();
								mIsSetting = false;
								NetworkGameScreen.this.setChildScene(mController);
							}
						});
						NetworkGameScreen.this.setChildScene(settingScene);
						mIsSetting = true;
					}else
					{
						NetworkGameScreen.this.clearChildScene();
						NetworkGameScreen.this.setChildScene(mController);
						mIsSetting = false;
					}
				}
				// TODO Auto-generated method stub
				return super
						.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
			}
		};
		
		mPauseButton = new AnimatedSprite(680, 5, ResourcesManager.getInstance().mPauseButtonTexture, mVertextManager)
		{
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN)
				{
					if(!mIsPause)
					{
						this.setCurrentTileIndex(2);
						this.setAlpha(1);
					}
					else
					{
						this.setCurrentTileIndex(3);
						this.setAlpha(1);
					}
					
				}
				if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP)
				{
					if(!mIsPause)
					{
						
						Packet pk = new Packet(CommandList.CLIENT_PAUSE,null);
						addPendingPacket(pk);
					}
					else
					{
						this.setAlpha(0.5f);
						Packet pk = new Packet(CommandList.CLIENT_RESUME,null);
						addPendingPacket(pk);
					}
				}
				
				// TODO Auto-generated method stub
				return super .onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
			}
		};
		
		
		ResourcesManager.getInstance().playMusic(typeMusic.MUTILGAME);
	}

	@Override
	public boolean onBackKeyPressed() {
		if(!mIsPause){
			ConfirmScreen sc =new ConfirmScreen("Do you want to exit game?\n" +
												"You will lose this game!",new ButtonDialogWatcher() {
				
				@Override
				public void onOkClick() {
					Packet pk = new Packet(CommandList.CLIENT_PLAYER_GIVEUP,null);
					addPendingPacket(pk);
					clearChildScene();
					setChildScene(mController);
					mIsSetting = false;
				}
				
				@Override
				public void onCancleClick() {
					clearChildScene();
					setChildScene(mController);
					mIsSetting = false;
				}
			});
			
			setChildScene(sc);
			
		}
		return true;
	}

	@Override
	public void onControlChange(BaseOnScreenControl pBaseOnScreenControl, float pValueX, float pValueY) {
		if(!mIsPause)
		{
			
			MovingDirection oldDir = mMyTank.getDir();
			MovingDirection newDir = oldDir;
			if (pValueY < 0 && !mMyTank.isMoving) 
				newDir = MovingDirection.UP;
			else if(pValueX > 0 && !mMyTank.isMoving)
				newDir = MovingDirection.RIGHT;
			else if(pValueY > 0 && !mMyTank.isMoving)
				newDir = MovingDirection.DOWN;
			else if(pValueX < 0 && !mMyTank.isMoving)
				newDir = MovingDirection.LEFT;
			
			if(pValueX!=0 || pValueY!=0) {
				if(!mMyTank.isMoving && !mIsSendingMove) {
					Packet pk = new Packet();
					pk.setCommand(CommandList.CLIENT_RUN);
					if(oldDir.ordinal() == newDir.ordinal()){
						pk.setData(CommandList.RUN_AHEAD+"");
					}else pk.setData(newDir.ordinal()+"");
					addPendingPacket(pk);
					mIsSendingMove = true;
				}
			}
		}	
	}
	
	private void pauseGame()
	{
		mIsPause = true;
		ResourcesManager.getInstance().pauseMusic();
	}
	
	private void resumeGame()
	{
		mIsPause = false;
		ResourcesManager.getInstance().playMusic(ResourcesManager.typeMusic.MUTILGAME);
	}

	@Override
	public SceneType getSceneType() {
		return SceneType.SCENE_GAME;
	}

	@Override
	public void disposeScene() {
		
	}
	
	@Override
	public void onUpdateScreen(float second) {
		MovePacket mpk = null;
		if(!mIsPause) {
			GameActivity.mGlobalMap.updateMarkedMatrix(mItanks);
			mpk = null;
			if(mMovingAction.size()>0)
				mpk = mMovingAction.get(0);
			if(mpk!=null){
				Tank tank = mpk.mAccountId == mMyAccount.getAccountId()?mMyTank:mCompetitorTank;
				if(!tank.isMoving) {
					mMovingAction.remove(0);
					switch(mpk.mDir){
					case CommandList.RUN_UP:
						tank.setDir(MovingDirection.UP);
						break;
					case CommandList.RUN_RIGHT:
						tank.setDir(MovingDirection.RIGHT);
						break;
					case CommandList.RUN_DOWN:
						tank.setDir(MovingDirection.DOWN);
						break;
					case CommandList.RUN_LEFT:
						tank.setDir(MovingDirection.LEFT);
						break;
					}
					if(mpk.mDir == CommandList.RUN_AHEAD && !tank.isTouchEdge())
						tank.doMove();
				}
				if(tank==mMyTank)
					mIsSendingMove = false;
			}
			
			for (int i = 0; i < mFlyTexts.size(); i++) {
				mFlyTexts.get(i).onUpdate();
				if(mFlyTexts.get(i).isIsDead())
				{
					mFlyTexts.get(i).detachSelf();
					mFlyTexts.remove(i); i--;
				}
			}
			for (int i = 0; i < mBullets.size(); i++) {
				Bullet bullet = mBullets.get(i);

				for(int j=0;j<mBullets.size();j++){
					Bullet b = mBullets.get(j);
					if(!b.isDead()&& bullet!= b && b.getShooter()!=bullet.getShooter() && bullet.collidesWith(b)){
						bullet.setDead(true);
						b.setDead(true);
						Explode ex = Explode.createExplode(bullet.getType()== BulletType.LASER?2:0, bullet.getCenterX(), bullet.getCenterY());
						mExplodes.add(ex);
						NetworkGameScreen.this.attachChild(ex);
						ex.start();
						break;
					}
				}
				
				if(!bullet.isDead()) {
					if(bullet.isCollisionWithMap(GameActivity.mGlobalMap) || bullet.isBreakOnMap(GameActivity.mGlobalMap)) 
					{
						bullet.setDead(true);
						Explode ex = Explode.createExplode(bullet.getType()==BulletType.LASER?2:1, bullet.getCenterX(), bullet.getCenterY());
						mExplodes.add(ex);
						NetworkGameScreen.this.attachChild(ex);
						ex.start();
					} else if (bullet.isCollisionWithITank(mItanks))
					{
						bullet.setDead(true);
						Explode ex = Explode.createExplode(bullet.getType()== BulletType.LASER?2:0, bullet.getCenterX(), bullet.getCenterY());
						mExplodes.add(ex);
						NetworkGameScreen.this.attachChild(ex);
						ex.start();
					}
					else
						bullet.onUpdate(GameActivity.mGlobalMap, second);
					
				}
				
				if(bullet.isDead()){
					mBullets.remove(i); i--;
					bullet.detachSelf();bullet.dispose();
				}
			}
			
			for(int i = 0; i< mExplodes.size(); i++){
				Explode ex = mExplodes.get(i);
				ex.onUpdate(null, second);
				if(ex.isDead()) {
					mExplodes.remove(i); i--;
					ex.detachSelf(); ex.dispose();
				}
			}
			
			for (int i = 0; i < mItanks.size(); i++) {
				ITank tank = mItanks.get(i);
				
				if(!tank.isDead()) {
					tank.findTarget(mMyTank);
					tank.onUpdate(GameActivity.mGlobalMap, second);
					if(tank.mIsAutoShoot){
						Bullet b = tank.shoot();
						mBullets.add(b); NetworkGameScreen.this.attachChild(b);
					}
				}
				else {
					mItanks.remove(i); i--;
					tank.detachSelf();
					onTankDead(tank);
				}
			}
			this.checkGameResult();
			
		}// end if(!mIsPause)
	}
	
	private void onTankDead(ITank tank){
		
		int currentHeart = tank.getHeart();
		if(currentHeart>0) {
			
			tank.setHeart(currentHeart-1);
			if(tank == mMyTank ){
				if(mMyAccount.getAccountId()==mMatch.getOwnerId()) {
					mMyTank.setX(0); mMyTank.setY(6*32);
					mMyTank.setDir(MovingDirection.RIGHT);
				}else {
					mMyTank.setX(24*32); mMyTank.setY(6*32);
					mMyTank.setDir(MovingDirection.LEFT);
				}
				
				mInfoBoard.setMyHeart(tank.getHeart());
			}else if(tank == mCompetitorTank){
				if(mCompetitorAccount.getAccountId()==mMatch.getOwnerId()) {
					mCompetitorTank.setX(0); mCompetitorTank.setY(6*32);
					mCompetitorTank.setDir(MovingDirection.RIGHT);
				}else {
					mCompetitorTank.setX(24*32); mCompetitorTank.setY(6*32);
					mCompetitorTank.setDir(MovingDirection.LEFT);
				}
				mInfoBoard.setCompetitorHeart(tank.getHeart());
			}
			tank.reset();tank.setDead(false);
			mItanks.add(tank);
			attachChild(tank);
		}else {
			ITank loseTank = tank;
			ITank winTank = tank == mCompetitorTank?mMyTank:mCompetitorTank;
			winTank.detachSelf();
			this.onGameEnd(winTank==mMyTank?mMyAccount:mCompetitorAccount,
							winTank==mMyTank?mCompetitorAccount:mMyAccount,
							winTank,loseTank);
		}
	}
	
	/**
	 * +Kiểm tra xem kết thúc game hay chưa
	 */
	private void checkGameResult(){
		for(int i=0;i<mItanks.size();i++){
			ITank tank = mItanks.get(i);
			if(tank.getHeart()<0){
				tank.detachSelf();
				ITank loseTank = tank;
				ITank winTank = tank == mCompetitorTank?mMyTank:mCompetitorTank;
				winTank.detachSelf();
				this.onGameEnd(winTank==mMyTank?mMyAccount:mCompetitorAccount,
								winTank==mMyTank?mCompetitorAccount:mMyAccount,
								winTank,loseTank);
				
				mItanks.remove(i); i--;
				break;
			}
		}
	}
	
	private void showFlyText(String s,float x,float y){
		FlyText ft = new FlyText(x,y);
		ft.setText(s);
		attachChild(ft);
		mFlyTexts.add(ft);
	}

	
	
	
	private void onGameEnd(Account winAccount,Account loseAccount,ITank winTank,ITank loseTank){
		mIsPause=true;
		
		ResourcesManager.getInstance().pauseMusic(typeMusic.MUTILGAME);
		if(winTank==mMyTank)
			ResourcesManager.getInstance().playSound(typeSound.WIN);
		else ResourcesManager.getInstance().playSound(typeSound.LOSE);
		
		MatchResultScreen.ResultDialogWatcher watcher = new MatchResultScreen.ResultDialogWatcher() {
			
			@Override
			public void onClose() {
				Packet pk = new Packet(CommandList.CLIENT_PLAY_DONE, null);
				addPendingPacket(pk);
				MatchListScreen sc = new MatchListScreen();
				SceneManager.getInstance().setScene(sc);
				mIsSetting = false;
			}
		};
		mResultDialogScreen = new MatchResultScreen(winAccount.getUsername(),
													loseAccount.getUsername(),
													winTank, loseTank,watcher);
		setChildScene(mResultDialogScreen);
		mIsSetting = true;
	}
	
	public void resetAllInfomation() {
		mPendingPackets.clear();
		
		if(getChildScene()== mResultDialogScreen && mResultDialogScreen!=null)
			mResultDialogScreen.detachSelf();
		if(GameActivity.mGlobalMap.loadMap(mMatch.getMapId())){
			
			mBullets.clear();
			mExplodes.clear();
			mItanks.clear();
			mFlyTexts.clear();

			mMyTank.setSpeed(GameSetting.SPEED_TANK);
			mMyTank.setHeart(GameSetting.PLAYER_HEART); mMyTank.setDead(false);
			if(mMyAccount.getAccountId()==mMatch.getOwnerId()) {
				mMyTank.setX(0); mMyTank.setY(6*32); 
				mMyTank.setDir(MovingDirection.RIGHT);
			}else {
				mMyTank.setX(24*32); mMyTank.setY(6*32);
				mMyTank.setDir(MovingDirection.LEFT);
			}
			
			mMyTank.reset();
			
			
			mCompetitorTank.setSpeed(GameSetting.SPEED_TANK);
			mCompetitorTank.setHeart(GameSetting.PLAYER_HEART); mCompetitorTank.setDead(false);
			mCompetitorTank.setX(24*32); mCompetitorTank.setY(6*32); 
			if(mCompetitorAccount.getAccountId()==mMatch.getOwnerId()) {
				mCompetitorTank.setX(0); mCompetitorTank.setY(6*32); 
				mCompetitorTank.setDir(MovingDirection.RIGHT);
			}else {
				mCompetitorTank.setX(24*32); mCompetitorTank.setY(6*32);
				mCompetitorTank.setDir(MovingDirection.LEFT);
			}
			mCompetitorTank.reset();
			mItanks.add(mMyTank); mItanks.add(mCompetitorTank);
			
			detachChildren();
			this.clearChildScene();
			this.clearTouchAreas();
			
			GameActivity.mGlobalMap.showMap(this);
			for (ITank tank : mItanks){
				attachChild(tank);
			}
			
			this.setChildScene(mController);
			this.registerTouchArea(mShootController);
			this.attachChild(mShootController);
			
			mInfoBoard.setMyHeart(mMyTank.getHeart());
			mInfoBoard.setCompetitorHeart(mCompetitorTank.getHeart());
			attachChild(mInfoBoard);
			
			mSettingButton.setCurrentTileIndex(0);
			mSettingButton.setAlpha(0.5f); mSettingButton.setZIndex(1);
			this.registerTouchArea(mSettingButton); this.attachChild(mSettingButton);

			mPauseButton.setCurrentTileIndex(0);
			mPauseButton.setAlpha(0.5f); mPauseButton.setZIndex(1);
			this.registerTouchArea(mPauseButton); this.attachChild(mPauseButton);
		}
		mIsPause = false;
	}

	
	private void registerPacketListener(){
		GameActivity.mClient.setPacketReceiver(new GamePlayingListener() {
			@Override
			public void onTankMoving(int accountId, int movingDir) {
				MovePacket pk = new MovePacket(accountId, movingDir);
				mMovingAction.add(pk);
			}

			@Override
			public void onFire(int accountid, float x, float y) {
				Tank tank = accountid == mMyAccount.getAccountId()?mMyTank:mCompetitorTank;
				if(!tank.isDead()) {
					Bullet b = tank.shoot(x, y);
					attachChild(b);
					mBullets.add(b);
				}
			}

			@Override
			public void onPause() {
				mPauseButton.setCurrentTileIndex(1);
				pauseGame();
			}

			@Override
			public void onResume() {
				mPauseButton.setCurrentTileIndex(0);
				resumeGame();
				
			}
			
			@Override
			public void onPlayerGiveUp(int accountId) {
				Tank tank = accountId==mMyAccount.getAccountId()?mMyTank:mCompetitorTank;
				tank.setHeart(-1);
			}
			
			@Override
			public void onServerDisconnected() {
				
			}
			
			@Override
			public void onDisconnected() {
				mIsPlaying = false;
				GameActivity.mClient.setAccount(null);
				MatchListScreen sc = new MatchListScreen();
				SceneManager.getInstance().setScene(sc);
			}
		});
	}
	
	private void addPendingPacket(Packet pk){
		try{
			synchronized(mPendingPackets){
				mPendingPackets.add(pk);
				mPendingPackets.notifyAll();
			}
		}catch(Exception ex){}
	}
	
	@Override
	public void run() {
		mIsPlaying = true;
		Packet pk = null;
		while(mIsPlaying){
			pk = null;
			try{
				synchronized(mPendingPackets){
					if(mPendingPackets.size()<=0)
						mPendingPackets.wait();
					pk = mPendingPackets.get(0);
				}
			}catch(Exception ex){}
			if(pk!=null){
				if(GameActivity.mClient.send(pk.getCommand(),pk.getData()!=null?pk.getData().getBytes():null)){
					synchronized (mPendingPackets) {
						mPendingPackets.remove(0);
					}
				}
				
				if(pk.getCommand() == CommandList.CLIENT_PLAY_DONE)
					mIsPlaying = false;
			}
		}
		mIsPlaying = false;
	}
}
